home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Tool Chest / Dev.CD Feb 97 TC.toast / Sample Code / Development Tools & Languages / AppsToGo / DTS.Lib / GWLayers.c < prev    next >
Encoding:
Text File  |  1994-09-22  |  33.5 KB  |  1,237 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        GWLayers.c
  6. ** Written by:  Eric Soldan and Forrest Tanaka
  7. **
  8. ** Copyright © 1989-1993 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20. /* This is an implementation of off-screen GWorld handling.  This particular
  21. ** implementation uses GWorlds in a hierarchical manner, with each layer in
  22. ** the hierarchy having its own tasks to handle at its specific level.
  23. ** The advantage to this is that it can conform to many applications.  Each
  24. ** application may need a different number of layers, and each layer may
  25. ** need to perform a different kind of operation.  By having an unlimited
  26. ** number of layers, and by having each layer handle its own application
  27. ** specific tasks, off-screen GWorld handling can be standardized.
  28. **
  29. ** A common use for off-screen stuff is to move an object around in a 
  30. ** window over a background.  To accomplish this, we need 3 layers.
  31. ** These are:
  32. **
  33. ** 1) The window layer.  This layer transfers a rectangle of pixels from
  34. **    the middle layer into the window layer, once the middle layer is ready.
  35. **    The rectangle transferred would be large enough to cover the old
  36. **    location and the new location, thus moving the piece without having
  37. **    to turn it off in the old location as a separate step.  This gives a
  38. **    very smooth appearance when moving an object.
  39. ** 2) A middle layer that is used to apply the object being moved to the
  40. **    background plus removing the object from the old location.  Once these
  41. **    two tasks are done, the off-screen work area is ready to be transferred
  42. **    to the window layer.
  43. ** 3) A background image against which the object moves.  This is used to
  44. **    restore the middle layer at the location where the object being moved
  45. **    was last at.
  46. **
  47. ** The top layer object relates to the window, and therefore we don't need an
  48. ** off-screen GWorld for it.  A call to create this layer might look like the below:
  49. **
  50. ** err = NewLayer(&windowLayer,   Layer object handle is returned here.
  51. **                nil,            Top layer, so there is no above layer.
  52. **                nil,            Uses default layer procedure.
  53. **                window,         Window used by the layer object.
  54. **                0,              Desired depth (0 for screen depth).
  55. **                0);             Custom layer init data, if any.
  56. **
  57. ** If NewLayer succeeds, the layer object handle is returned in windowLayer.
  58. ** If it fails, nil is returned in windowLayer, plus an error is returned.
  59. ** If windowLayer is successfully created, then we can proceed to create the
  60. ** next two layers.  In the case below, we are creating an off-screen layer
  61. ** that has a pixmap the same size and depth as windowLayer.  If this is
  62. ** what we want for the middle layer, then we can again use the default
  63. ** LayerProc for the kLayerInit message.  All we need to do is to call the
  64. ** default layerProc with a kLayerInit message.  We want the standard
  65. ** action for initialization, but we want our own update action.  That's
  66. ** why we have a custom layerProc for the middle layer.  The call would look
  67. ** something like the below:
  68. **
  69. ** err = NewLayer(&middleLayer,     Layer object handle is returned here.
  70. **                windowLayer,      Layer above this layer.
  71. **                MiddleLayerProc,  Custom layerProc.
  72. **                nil,              Create a pixmap for layer.
  73. **                0,                Pixmap created as same size/depth as above layer.
  74. **                0);
  75. **
  76. ** The background layer would be created similarly.  When you are finished with
  77. ** the layers, you can dispose of them one at a time with DisposeLayer, or you
  78. ** can dispose of all of them in the layer chain with DisposeThisAndBelowLayers.
  79. **
  80. ** Inserting a layer is done by position, and not by which layer it goes above
  81. ** or below.  The reason for this is that the layer positions are most likely
  82. ** absolute, and therefore it is better to indicate their position with an
  83. ** absolute number instead of always relating it to some other layer.  If it
  84. ** is necessary to insert a layer specifically above or below some other layer,
  85. ** it would be done as follows:
  86. **         InsertLayer(newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  87. **         InsertLayer(newLayer, belowLayer, GetLayerPosition(belowLayer));
  88. **
  89. ** The sample applications DTS.Draw and Kibitz uses the off-screen layer code.
  90. ** For a sample usage, see the file Window2.c in DTS.Draw, or Offscreen.c in Kibitz.
  91. */
  92.  
  93.  
  94.  
  95. /*****************************************************************************/
  96.  
  97.  
  98.  
  99. #ifndef __ERRORS__
  100. #include <Errors.h>
  101. #endif
  102.  
  103. #ifndef __GESTALTEQU__
  104. #include <GestaltEqu.h>
  105. #endif
  106.  
  107. #ifndef __GWLAYERS__
  108. #include "GWLayers.h"
  109. #endif
  110.  
  111. #ifndef __RESOURCES__
  112. #include <Resources.h>
  113. #endif
  114.  
  115. #ifndef __STRINGUTILS__
  116. #include <StringUtils.h>
  117. #endif
  118.  
  119. #ifndef __TRAPS__
  120. #include <Traps.h>
  121. #endif
  122.  
  123. #ifndef __WINDOWS__
  124. #include <Windows.h>
  125. #endif
  126.  
  127. #define kQDOriginal 0
  128.  
  129. static OSErr    DefaultLayerInit(LayerObj theLayer);
  130. static OSErr    DefaultLayerUpdate(LayerObj theLayer);
  131. static OSErr    DefaultLayerDispose(LayerObj theLayer);
  132.  
  133. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds);
  134. static void        KillLayerWorld(LayerObj theLayer);
  135. static void        SmartGetGWorld(CGrafPtr *port, GDHandle *gdh);
  136. static void        SmartSetGWorld(CGrafPtr port, GDHandle gdh);
  137. static short    GetQDVersion(void);
  138. static short    GetSystemVersion(void);
  139. static short    NumToolboxTraps(void);
  140. static Boolean    TrapExists(short theTrap);
  141. static TrapType    GetTrapType(short theTrap);
  142.  
  143.  
  144.  
  145. /*****************************************************************************/
  146. /*****************************************************************************/
  147.  
  148. #ifdef applec
  149. #pragma segment ATGGWLayers
  150. #endif
  151.  
  152. /*****************************************************************************/
  153. /*****************************************************************************/
  154.  
  155.  
  156.  
  157. OSErr    NewLayer(LayerObj *newLayer, LayerObj aboveLayer, LayerProc theProc,
  158.                  GrafPtr basePort, short depth, unsigned long theData)
  159. {
  160.     OSErr        err;
  161.     LayerRecPtr    lptr;
  162.     CGrafPtr    scratchPort;
  163.     GDHandle    baseGDevice;
  164.  
  165.     *newLayer = (LayerObj)NewHandleClear(sizeof(LayerRec));
  166.     err = MemError();
  167.     if (err) return(err);
  168.         /* If not enough memory for layer object, return nil and error. */
  169.  
  170.     SmartGetGWorld(&scratchPort, &baseGDevice);
  171.     if (!theProc)
  172.         theProc = DefaultLayerProc;
  173.             /* If layer proc is nil, then they want the default behavior. */
  174.  
  175.     lptr = **newLayer;
  176.     lptr->layerPort     = basePort;
  177.     lptr->layerGDevice  = baseGDevice;
  178.     lptr->layerDepth    = depth;
  179.     lptr->xferMode      = srcCopy;
  180.     lptr->layerProc     = theProc;
  181.     lptr->layerData     = theData;
  182.         /* Layer object is now initialized, except for layers that need a GWorld
  183.         ** created.  This will occur when the layer proc is called with an
  184.         ** initialization message.  (All fields not explicitly set are 0.) */
  185.  
  186.     InsertLayer(*newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  187.         /* Connect the layer to the layer chain.  The default initialization
  188.         ** behavior may need this, as it may create a GWorld of the same size
  189.         ** as the above layer.  If it isn't connected to the layer chain, then
  190.         ** there is no above layer. */
  191.  
  192.     err = (*theProc)(*newLayer, kLayerInit);
  193.     if (err) {
  194.         DisposeLayer(*newLayer);
  195.         *newLayer = nil;
  196.             /* There wasn't enough memory to create the off-screen GWorld, so
  197.             ** dispose of the layer object.  Since we failed, we need to return
  198.             ** nil and the error. */
  199.     }
  200.  
  201.     return(err);
  202. }
  203.  
  204.  
  205.  
  206. /*****************************************************************************/
  207.  
  208.  
  209.  
  210. void    DetachLayer(LayerObj theLayer)
  211. {
  212.     LayerObj    aboveLayer, belowLayer;
  213.  
  214.     if (theLayer) {
  215.         aboveLayer = (*theLayer)->aboveLayer;
  216.         belowLayer = (*theLayer)->belowLayer;
  217.         if (aboveLayer)
  218.             (*aboveLayer)->belowLayer = belowLayer;
  219.         if (belowLayer)
  220.             (*belowLayer)->aboveLayer = aboveLayer;
  221.         (*theLayer)->aboveLayer = (*theLayer)->belowLayer = nil;
  222.     }
  223. }
  224.  
  225.  
  226.  
  227. /*****************************************************************************/
  228.  
  229.  
  230.  
  231. OSErr    DisposeLayer(LayerObj theLayer)
  232. {
  233.     OSErr    err;
  234.  
  235.     err = noErr;
  236.     if (theLayer) {
  237.         err = (*((*theLayer)->layerProc))(theLayer, kLayerDispose);
  238.         DetachLayer(theLayer);
  239.         DisposeHandle((Handle)theLayer);
  240.     }
  241.  
  242.     return(err);
  243. }
  244.  
  245.  
  246.  
  247. /*****************************************************************************/
  248.  
  249.  
  250.  
  251. OSErr    DisposeThisAndBelowLayers(LayerObj theLayer)
  252. {
  253.     OSErr    err, err2;
  254.  
  255.     err = noErr;
  256.     if (theLayer) {
  257.         err2 = DisposeThisAndBelowLayers((*theLayer)->belowLayer);
  258.         err  = DisposeLayer(theLayer);
  259.         if (!err)
  260.             err = err2;
  261.     }
  262.     return(err);
  263. }
  264.  
  265.  
  266.  
  267. /*****************************************************************************/
  268.  
  269.  
  270.  
  271. short    GetLayerPosition(LayerObj theLayer)
  272. {
  273.     short    pos;
  274.  
  275.     if (!theLayer) return(0);
  276.  
  277.     for (pos = 0; (theLayer = (*theLayer)->aboveLayer) != nil; ++pos) {};
  278.     return(pos);
  279. }
  280.  
  281.  
  282.  
  283. /*****************************************************************************/
  284.  
  285.  
  286.  
  287. LayerObj    GetTopLayer(LayerObj theLayer)
  288. {
  289.     for (; (*theLayer)->aboveLayer; theLayer = (*theLayer)->aboveLayer) {};
  290.     return(theLayer);
  291. }
  292.  
  293.  
  294.  
  295. /*****************************************************************************/
  296.  
  297.  
  298.  
  299. LayerObj    GetBottomLayer(LayerObj theLayer)
  300. {
  301.     for (; (*theLayer)->belowLayer; theLayer = (*theLayer)->belowLayer) {};
  302.     return(theLayer);
  303. }
  304.  
  305.  
  306.  
  307. /*****************************************************************************/
  308.  
  309.  
  310.  
  311. void    InsertLayer(LayerObj theLayer, LayerObj referenceLayer, short pos)
  312. {
  313.     LayerObj    aboveLayer, belowLayer;
  314.     short        i;
  315.  
  316.     if (theLayer) {
  317.         if (theLayer == referenceLayer) {
  318.             /* If theLayer layer is the same as referenceLayer... */
  319.  
  320.             belowLayer = (*theLayer)->belowLayer;
  321.             if (belowLayer)
  322.                 referenceLayer = belowLayer;
  323.             aboveLayer = (*theLayer)->aboveLayer;
  324.             if (aboveLayer)
  325.                 referenceLayer = aboveLayer;
  326.                     /* Try to make the reference layer not the same as theLayer.
  327.                     ** If it is the same as theLayer, then when theLayer is
  328.                     ** removed from the old hierarchy, we lose the ability to re-add
  329.                     ** it to the hierarchy in a new location. */
  330.         }
  331.  
  332.         DetachLayer(theLayer);
  333.             /* Remove layer from its old hierarchy, if any. */
  334.  
  335.         if (!referenceLayer) return;
  336.             /* If there isn't a valid alternative reference, then theLayer
  337.             ** IS the hierarchy and no action is taken. */
  338.  
  339.         aboveLayer = nil;
  340.         belowLayer = GetTopLayer(referenceLayer);
  341.             /* aboveLayer now nil.  belowLayer now is top layer.  These
  342.             ** are the correct values if the layer being added is to be
  343.             ** the new top layer.  This will be the case if pos is 0.
  344.             ** We now walk the linked list pos number of times to get the
  345.             ** correct position.  We also terminate if we reach the end
  346.             ** of the linked list, no matter what pos is.  This will allow
  347.             ** values of pos that are too big to insert the layer at the
  348.             ** end of the linked list. */
  349.  
  350.         for (i = 0; ((belowLayer) && (i != pos)); ++i) {
  351.             aboveLayer = belowLayer;
  352.             belowLayer = (*belowLayer)->belowLayer;
  353.         }
  354.             /* We now have correct values for aboveLayer and belowLayer.  Note that
  355.             ** these values may be nil, which would be correct. */
  356.         (*theLayer)->aboveLayer = aboveLayer;
  357.         if (aboveLayer)
  358.             (*aboveLayer)->belowLayer = theLayer;
  359.         (*theLayer)->belowLayer = belowLayer;
  360.         if (belowLayer)
  361.             (*belowLayer)->aboveLayer = theLayer;
  362.     }
  363. }
  364.  
  365.  
  366.  
  367. /*****************************************************************************/
  368.  
  369.  
  370.  
  371. /*****************************************************************************/
  372.  
  373.  
  374.  
  375. OSErr    UpdateLayer(LayerObj theLayer)
  376. {
  377.     OSErr    err;
  378.  
  379.     err = noErr;
  380.     if (theLayer) {
  381.         err = UpdateLayer((*theLayer)->belowLayer);
  382.             /* Handle the updates from the bottom up. */
  383.         if (!err)
  384.             err = (*((*theLayer)->layerProc))(theLayer, kLayerUpdate);
  385.                 /* Chain possible errors through each level of recursion. */
  386.     }
  387.     return(err);
  388. }
  389.  
  390.  
  391.  
  392. /*****************************************************************************/
  393.  
  394.  
  395.  
  396. Rect    GetEffectiveSrcRect(LayerObj theLayer)
  397. {
  398.     Rect    srcRect;
  399.  
  400.     if (!theLayer)
  401.         SetRect(&srcRect, 0, 0, 0, 0);
  402.     else {
  403.         srcRect = (*theLayer)->srcRect;
  404.         if (EmptyRect(&srcRect))
  405.             srcRect = ((*theLayer)->layerPort)->portRect;
  406.     }
  407.     return(srcRect);
  408. }
  409.  
  410.  
  411.  
  412. /*****************************************************************************/
  413.  
  414.  
  415.  
  416. Rect    GetEffectiveDstRect(LayerObj theLayer)
  417. {
  418.     Rect    dstRect;
  419.  
  420.     if (!theLayer)
  421.         SetRect(&dstRect, 0, 0, 0, 0);
  422.     else {
  423.         dstRect = (*theLayer)->dstRect;
  424.         if (EmptyRect(&dstRect))
  425.             dstRect = ((*theLayer)->layerPort)->portRect;
  426.     }
  427.     return(dstRect);
  428. }
  429.  
  430.  
  431.  
  432. /*****************************************************************************/
  433.  
  434.  
  435.  
  436. OSErr    DefaultLayerProc(LayerObj theLayer, short message)
  437. {
  438.     OSErr    err;
  439.  
  440.     err = noErr;
  441.     if (theLayer) {
  442.         switch (message) {        /* Dispatch to the correct default behavior. */
  443.             case kLayerInit:
  444.                 err = DefaultLayerInit(theLayer);
  445.                 break;
  446.             case kLayerDispose:
  447.                 err = DefaultLayerDispose(theLayer);
  448.                 break;
  449.             case kLayerUpdate:
  450.                 err = DefaultLayerUpdate(theLayer);
  451.                 break;
  452.             default:
  453.                 break;
  454.         }
  455.     }
  456.     return(err);
  457. }
  458.  
  459.  
  460.  
  461. /*****************************************************************************/
  462.  
  463.  
  464.  
  465. Rect    UpdateUpdateRects(LayerObj theLayer)
  466. {
  467.     Rect    lastUpdate, thisUpdate, dstRect;
  468.  
  469.     if (theLayer) {
  470.         lastUpdate = (*theLayer)->lastUpdate;
  471.         (*theLayer)->lastUpdate = thisUpdate = (*theLayer)->thisUpdate;
  472.         SetRect(&((*theLayer)->thisUpdate), 0, 0, 0, 0);
  473.  
  474.         if ((*theLayer)->includeLastUpdate) {
  475.             (*theLayer)->includeLastUpdate = false;
  476.             if (EmptyRect(&lastUpdate))
  477.                 lastUpdate = thisUpdate;
  478.             if (EmptyRect(&thisUpdate))
  479.                 thisUpdate = lastUpdate;
  480.             UnionRect(&thisUpdate, &lastUpdate, &thisUpdate);
  481.                 /* We are going to update the last and current update rects.
  482.                 ** This will allow the appearance of movement for a foreground
  483.                 ** object.  The old location is cleared, plus the new location
  484.                 ** is updated. */
  485.             dstRect = GetEffectiveDstRect(theLayer);
  486.             SectRect(&thisUpdate, &dstRect, &thisUpdate);
  487.         }
  488.     }
  489.     else SetRect(&thisUpdate, 0, 0, 0, 0);
  490.  
  491.     return(thisUpdate);
  492. }
  493.  
  494.  
  495.  
  496. /*****************************************************************************/
  497.  
  498.  
  499.  
  500. void    InvalLayer(LayerObj theLayer, Rect invalRect, Boolean includeLastUpdate)
  501. {
  502.     Rect        thisUpdate, srcRect, dstRect;
  503.     LayerObj    belowLayer;
  504.     short        ow, oh;
  505.     long        dw, dh, sw, sh;
  506.  
  507.     if (theLayer) {
  508.         belowLayer = (*theLayer)->belowLayer;
  509.         dstRect    = GetEffectiveDstRect(theLayer);
  510.  
  511.         SectRect(&dstRect, &invalRect, &invalRect);
  512.         if (!EmptyRect(&invalRect)) {                /* If there is something to invalidate... */
  513.             thisUpdate = (*theLayer)->thisUpdate;    /* There may be a prior unhandled update... */
  514.             if (EmptyRect(&thisUpdate))
  515.                 thisUpdate = invalRect;                /* UnionRect doesn't */
  516.             UnionRect(&thisUpdate, &invalRect, &(*theLayer)->thisUpdate);    /* like empty rects. */
  517.  
  518.             if (belowLayer) {
  519.                 /* If we have a below layer, then pass the update down.  The effectiveSrcRct
  520.                 ** rect for the below layer may be a different size than the effectiveDstRct.
  521.                 ** If this is the case, we want to scale invalRect to invalidate a proportional
  522.                 ** area in the below layer. */
  523.  
  524.                 srcRect = GetEffectiveSrcRect(belowLayer);
  525.  
  526.                 dw = dstRect.right  - dstRect.left;        /* Calculate widths and heights for */
  527.                 dh = dstRect.bottom - dstRect.top;        /* srcRect and dstRect. */
  528.                 sw = srcRect.right  - srcRect.left;
  529.                 sh = srcRect.bottom - srcRect.top;
  530.  
  531.                 OffsetRect(&invalRect, -dstRect.left, -dstRect.top);
  532.                     /* We want to align the upper-left corner of the srcRect and dstRect
  533.                     ** so that the scaling also aligns the invalRect into the correct
  534.                     ** place in the below layer's effectiveSrcRect.  invalRect is now
  535.                     ** positioned relative to a dstRect with a upper-left corner of 0,0. */
  536.  
  537.                 if (dw != sw) {        /* Width dstRect different than srcRect. */
  538.                     ow = invalRect.right  - invalRect.left;
  539.                     invalRect.left  = (short)((invalRect.left  * sw) / dw);
  540.                     invalRect.right = (short)((invalRect.right * sw) / dw);
  541.                     if ((((invalRect.right  - invalRect.left) * dw) / sw) != ow)
  542.                         ++invalRect.right;
  543.                             /* We can possibly lose a fraction of a pixel on the right edge when
  544.                             ** scaling the invalRect.  It won't hurt if we inval just a bit too
  545.                             ** much, whereas invalidating too little is a bad thing. */
  546.                 }
  547.  
  548.                 if (dh != sh) {        /* Height dstRect different than srcRect. */
  549.                     oh = invalRect.bottom - invalRect.top;
  550.                     invalRect.top    = (short)((invalRect.top    * sh) / dh);
  551.                     invalRect.bottom = (short)((invalRect.bottom * sh) / dh);
  552.                     if ((((invalRect.bottom - invalRect.top ) * dh) / sh) != oh)
  553.                         ++invalRect.bottom;
  554.                 }
  555.  
  556.                 OffsetRect(&invalRect, srcRect.left, srcRect.top);
  557.                     /* Displace the new invalRect correctly relative to the srcRect. */
  558.             }
  559.         }
  560.  
  561.         if (includeLastUpdate)
  562.             (*theLayer)->includeLastUpdate = true;
  563.                 /* If requested to update last position as well, flag it. */
  564.  
  565.         InvalLayer(belowLayer, invalRect, includeLastUpdate);
  566.             /* Invalidate the below layer with the new (possibly scaled) invalRect. */
  567.     }
  568. }
  569.  
  570.  
  571. /*****************************************************************************/
  572.  
  573.  
  574.  
  575. void    SetLayerWorld(LayerObj theLayer)
  576. {
  577.     CGrafPtr    keepPort;
  578.     GDHandle    keepGDevice;
  579.  
  580.     /* This is a convenient call for setting a GWorld, while remembering what
  581.     ** the previous GWorld was.  This should be balanced with a call to
  582.     ** ResetLayerWorld.  A count of how many times this is called is kept
  583.     ** so that the old GWorld is cached only if SetLayerWorld is currently
  584.     ** in balance with ResetLayerWorld.  This keeps the oldest kept GWorld
  585.     ** from being overwritten by subsequent calls. */
  586.  
  587.     if (theLayer) {
  588.         if (!(*theLayer)->cachedCount++) {
  589.             SmartGetGWorld(&keepPort, &keepGDevice);
  590.             (*theLayer)->cachedPort    = keepPort;
  591.             (*theLayer)->cachedGDevice = keepGDevice;
  592.         }
  593.         SmartSetGWorld((CGrafPtr)(*theLayer)->layerPort, (*theLayer)->layerGDevice);
  594.         LockLayerWorld(theLayer);
  595.     }
  596. }
  597.  
  598.  
  599.  
  600. /*****************************************************************************/
  601.  
  602.  
  603.  
  604. void    ResetLayerWorld(LayerObj theLayer)
  605. {
  606.     /* This is used to undo a call to SetLayerWorld.  Calls to ResetLayerWorld
  607.     ** should be balanced with previous calls to SetLayerWorld. */
  608.  
  609.     if (theLayer) {
  610.         UnlockLayerWorld(theLayer);
  611.         if (!--(*theLayer)->cachedCount)
  612.             SmartSetGWorld((*theLayer)->cachedPort, (*theLayer)->cachedGDevice);
  613.     }
  614. }
  615.  
  616.  
  617.  
  618. /*****************************************************************************/
  619.  
  620.  
  621.  
  622. void    LockLayerWorld(LayerObj theLayer)
  623. {
  624.     Handle    bitmap;
  625.  
  626.     /* This is a convenient way to lock down the pixels for a layer's GWorld.
  627.     ** A locked count is kept to make sure that the GWorld is locked only the
  628.     ** first time this is called.  Calls to LockLayerWorld will most likely
  629.     ** be balanced by calls to UnlockLayerWorld, but not necessarily.  It may
  630.     ** be desirable to keep a GWorld call locked.  In this case, right after
  631.     ** creating the layer (and indirectly its GWorld), call LockLayerWorld.
  632.     ** This will initially lock it.  Subsequent calls would be balanced, and
  633.     ** therefore there will always be one more LockLayerWorld call than
  634.     ** UnlockLayerWorld calls.  This will keep it locked. */
  635.  
  636.     if (theLayer) {
  637.         if ((*theLayer)->layerOwnsPort) {
  638.             if (!(*theLayer)->lockedCount++) {
  639.                 bitmap = (*theLayer)->layerBitmap;
  640.                 if (bitmap) {
  641.                     HLock(bitmap);
  642.                     (*theLayer)->layerPort->portBits.baseAddr = *bitmap;
  643.                 }
  644.                 else
  645.                     LockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  646.             }
  647.         }
  648.     }
  649. }
  650.  
  651.  
  652.  
  653. /*****************************************************************************/
  654.  
  655.  
  656.  
  657. void    UnlockLayerWorld(LayerObj theLayer)
  658. {
  659.     /* This undoes what LockLayerWorld does.  Calls to UnlockLayerWorld will
  660.     ** generally be balanced with calls to LockLayerWorld. */
  661.  
  662.     if (theLayer) {
  663.         if ((*theLayer)->layerOwnsPort) {
  664.             if (!--(*theLayer)->lockedCount) {
  665.                 if ((*theLayer)->layerBitmap)
  666.                     HUnlock((*theLayer)->layerBitmap);
  667.                 else
  668.                     UnlockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  669.             }
  670.         }
  671.     }
  672. }
  673.  
  674.  
  675.  
  676. /*****************************************************************************/
  677.  
  678.  
  679.  
  680. RgnHandle    ScreenDepthRegion(short depth)
  681. {
  682.     RgnHandle        retRgn, tmpRgn;
  683.     GDHandle        device;
  684.     PixMapHandle    pmap;
  685.     Rect            rct;
  686.     GrafPtr            mainPort;
  687.  
  688.     retRgn = NewRgn();
  689.  
  690.     if (GetQDVersion() == kQDOriginal) {
  691.         if (depth == 1) {
  692.             GetWMgrPort(&mainPort);
  693.             rct = mainPort->portRect;
  694.             RectRgn(retRgn, &rct);
  695.         }
  696.     }
  697.     else {
  698.         tmpRgn = NewRgn();
  699.         for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  700.             if (
  701.                 (TestDeviceAttribute(device, screenDevice)) &&
  702.                 (TestDeviceAttribute(device, screenActive))
  703.             ) {
  704.                 pmap = (*device)->gdPMap;
  705.                 if ((*pmap)->pixelSize >= depth) {
  706.                     rct = (*device)->gdRect;
  707.                     RectRgn(tmpRgn, &rct);
  708.                     UnionRgn(retRgn, tmpRgn, retRgn);
  709.                 }
  710.             }
  711.         }
  712.         DisposeRgn(tmpRgn);
  713.     }
  714.  
  715.     return(retRgn);
  716. }
  717.  
  718.  
  719.  
  720. /*****************************************************************************/
  721.  
  722.  
  723.  
  724. CIconHandle    ReadCIcon(short iconID)
  725. {
  726.     Handle    hndl;
  727.  
  728.     if (TrapExists(_PlotCIcon))
  729.         return(GetCIcon(iconID));
  730.  
  731.     hndl = GetResource('cicn', iconID);
  732.     DetachResource(hndl);
  733.     return((CIconHandle)hndl);
  734. }
  735.  
  736.  
  737.  
  738. /*****************************************************************************/
  739.  
  740.  
  741.  
  742. void    KillCIcon(CIconHandle icon)
  743. {
  744.     if (!icon) return;
  745.  
  746.     if (TrapExists(_PlotCIcon))
  747.         DisposeCIcon(icon);
  748.     else
  749.         DisposeHandle((Handle)icon);
  750. }
  751.  
  752.  
  753.  
  754. /*****************************************************************************/
  755.  
  756.  
  757.  
  758. void    DrawCIcon(CIconHandle icon, Rect destRect)
  759. {
  760.     WindowPtr    curPort;
  761.     short        depth;
  762.  
  763.     if (!icon) return;
  764.  
  765.     if (TrapExists(_PlotCIcon)) {
  766.         depth = 8;
  767.         if (GetSystemVersion() < 0x0700) {
  768.             depth = 1;
  769.             GetPort(&curPort);
  770.             if (curPort->portBits.rowBytes & 0x8000)
  771.                 depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
  772.         }
  773.     }
  774.     else depth = 1;
  775.  
  776.     if (depth > 1)
  777.         PlotCIcon(&destRect, icon);
  778.     else
  779.         DrawCIconByDepth(icon, destRect, 1, true);
  780. }
  781.  
  782.  
  783.  
  784. /*****************************************************************************/
  785.  
  786.  
  787.  
  788. void    DrawCIconNoMask(CIconHandle icon, Rect destRect)
  789. {
  790.     Rect    iconRect;
  791.     char    oldMask[128], *mptr;
  792.     short    maskSize, i;
  793.  
  794.     if (!icon) return;
  795.  
  796.     mptr = (Ptr)(*icon)->iconMaskData;
  797.     iconRect = (*icon)->iconPMap.bounds;
  798.     maskSize = (iconRect.bottom - iconRect.top) * (*icon)->iconMask.rowBytes;
  799.     for (i = 0; i < maskSize; ++i) {
  800.         oldMask[i] = mptr[i];
  801.         mptr[i] = 0xFF;
  802.     }
  803.     DrawCIcon(icon, destRect);
  804.     mptr = (Ptr)(*icon)->iconMaskData;
  805.     for (i = 0; i < maskSize; ++i) mptr[i] = oldMask[i];
  806. }
  807.  
  808.  
  809.  
  810. /*****************************************************************************/
  811.  
  812.  
  813.  
  814. void    DrawCIconByDepth(CIconHandle icon, Rect destRect, short depth, Boolean useMask)
  815. {
  816.     GrafPtr        curPort;
  817.     char        savedIconState;
  818.     char        savedDataState;
  819.     short        offset;
  820.     BitMapPtr    bmap;
  821.     Rect        iconRect;
  822.  
  823.     if (!icon) return;
  824.  
  825.     GetPort(&curPort);
  826.  
  827.     if (!depth) {
  828.         if (!(curPort->portBits.rowBytes & 0x8000))
  829.             depth = 1;
  830.         else
  831.             depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
  832.     }
  833.  
  834.     savedIconState = HGetState((Handle)icon);        /* Lock down things. */
  835.     HLock((Handle)icon);
  836.     if (depth > 1) {
  837.         savedDataState = HGetState((*icon)->iconData);
  838.         HLock((*icon)->iconData);
  839.         (*icon)->iconPMap.baseAddr = *((*icon)->iconData);
  840.             /* Point the icon's pixMap at the color icon data. */
  841.     }
  842.  
  843.     iconRect = (*icon)->iconPMap.bounds;
  844.         /* Find out the dimensions of the icon. */
  845.  
  846.     (*icon)->iconMask.baseAddr = (Ptr)(*icon)->iconMaskData;
  847.         /* Point the mask's bitMap at the mask data. */
  848.  
  849.     offset  = iconRect.bottom - iconRect.top;
  850.     offset *= (*icon)->iconMask.rowBytes;
  851.     (*icon)->iconBMap.baseAddr = (*icon)->iconMask.baseAddr + offset;
  852.         /* Point the icon's bitMap at the b/w icon data. */
  853.  
  854.     bmap = (depth == 1) ? (BitMapPtr)&((*icon)->iconBMap) : (BitMapPtr)&((*icon)->iconPMap);
  855.     if (useMask)
  856.         CopyMask(bmap, &((*icon)->iconMask), &curPort->portBits, &iconRect, &iconRect, &destRect);
  857.     else
  858.         CopyBits(bmap, &curPort->portBits, &iconRect, &destRect, srcCopy, nil);
  859.  
  860.     HSetState((Handle)icon, savedIconState);        /* Unlock things. */
  861.     if (depth > 1)
  862.         HSetState((*icon)->iconData, savedDataState);
  863. }
  864.  
  865.  
  866.  
  867. /*****************************************************************************/
  868. /*****************************************************************************/
  869. /*****************************************************************************/
  870.  
  871.  
  872.  
  873. static OSErr    DefaultLayerInit(LayerObj theLayer)
  874. {
  875.     LayerObj    aboveLayer;
  876.     GWorldPtr    layerWorld;        /* GWorld for this layer. */
  877.     Rect        parentRect;        /* Rectangle of parent in global coordinates. */
  878.     GrafPtr        parentPort;        /* Parent layer's GrafPort. */
  879.     GDHandle    parentGDevice;    /* Parent layer's GDevice. */
  880.     CGrafPtr    keepPort;        /* Saved GrafPort. */
  881.     GDHandle    keepGDevice;    /* Saved GDevice. */
  882.     Point        org;
  883.     OSErr        err;
  884.     short        depth;
  885.  
  886.     err = noErr;
  887.     if (theLayer) {
  888.         if (!(*theLayer)->layerPort) {
  889.  
  890.             aboveLayer = (*theLayer)->aboveLayer;
  891.             if (aboveLayer) {
  892.                 /* The default behavior is to create a GWorld the same size
  893.                 ** as the above layer, if there is one.  If there isn't an above
  894.                 ** layer and we were expected to create a GWorld, we have problems.
  895.                 ** This situation can't be resolved and is handled as a paramErr. */
  896.  
  897.                 if (!((*theLayer)->layerDepth))
  898.                     (*theLayer)->layerDepth = (*aboveLayer)->layerDepth;
  899.  
  900.                 SmartGetGWorld(&keepPort, &keepGDevice);        /* Keep the GWorld. */
  901.  
  902.                 parentPort    = (*aboveLayer)->layerPort;
  903.                 parentGDevice = (*aboveLayer)->layerGDevice;
  904.                     /* Grab the parent layer's GrafPort and GDevice. */
  905.     
  906.                 SmartSetGWorld((CGrafPtr)parentPort, parentGDevice);
  907.                 parentRect = GetEffectiveDstRect(aboveLayer);
  908.                     /* The default behavior is to use the portRect of the above
  909.                     ** port.  This behavior can be overridden if desired by setting
  910.                     ** dstRect.  dstRect is initialized to be empty, but if
  911.                     ** it is specifically set, then this layer should map into
  912.                     ** just the dstRect and not the portRect.  This is useful if
  913.                     ** the off-screen image is to be displayed in only a portion
  914.                     ** of a window. */
  915.  
  916.                 org.h = parentRect.left;
  917.                 org.v = parentRect.top;
  918.  
  919.                 LocalToGlobal(((Point *)&parentRect) + 0);
  920.                 LocalToGlobal(((Point *)&parentRect) + 1);
  921.                     /* Put the parent layer's destination rect in global coordinates. */
  922.     
  923.                 if (GetQDVersion())
  924.                     err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &parentRect, nil, nil, 0);
  925.                         /* Create the GWorld for this layer.  It will be created with the
  926.                         ** requested depth.  If the requested depth is 0, then it will be
  927.                         ** created with a depth great enough for the deepest monitor the
  928.                         ** parentRect intersects. */
  929.                 else
  930.                     err = MakeLayerWorld(&layerWorld, theLayer, parentRect);
  931.                         /* Create a bitmap for those systems without GWorlds. */
  932.  
  933.                 if (err == noErr) {
  934.                     (*theLayer)->layerOwnsPort = true;
  935.                     SetPort((*theLayer)->layerPort = (GrafPtr)layerWorld);
  936.                         /* Save the new GWorld in the layer object. */
  937.                     SetOrigin(org.h, org.v);
  938.                         /* Set the origin so that this GWorld maps directly into the
  939.                         ** area to be copied into (dstRect or portRect) for the
  940.                         ** above layer. */
  941.  
  942.                     if (!((*theLayer)->layerDepth)) {
  943.                         if (((GrafPtr)layerWorld)->portBits.rowBytes & 0x8000)
  944.                             depth = (*(((CGrafPtr)layerWorld)->portPixMap))->pixelSize;
  945.                         else
  946.                             depth = 1;
  947.                         (*theLayer)->layerDepth = depth;
  948.                     }
  949.                 }
  950.  
  951.                 SmartSetGWorld(keepPort, keepGDevice);        /* Restore the kept GWorld. */
  952.             }
  953.             else {
  954.                 err = paramErr;
  955.                     /* We were expected to create an off-screen GWorld of the
  956.                     ** same size as the above layer, but we didn't have an above
  957.                     ** layer.  This is an error.  The parameters passed to NewLayer
  958.                     ** were inappropriate for the situation, so return a paramErr. */
  959.             }
  960.         }
  961.     }
  962.  
  963.     return(err);
  964. }
  965.  
  966.  
  967.  
  968. /*****************************************************************************/
  969.  
  970.  
  971.  
  972. static OSErr    DefaultLayerUpdate(LayerObj theLayer)
  973. {
  974.     LayerObj    belowLayer;
  975.     GrafPtr        belowPort, thisPort;
  976.     GDHandle    thisGDevice;
  977.     CGrafPtr    keepPort;
  978.     GDHandle    keepGDevice;
  979.     Rect        thisUpdate, belowRect, thisRect;
  980.     short        xfer;
  981.     RgnHandle    rgn;
  982.  
  983.     /* The default update behavior is to copy the area to be updated from the
  984.     ** below layer into the indicated layer.  We only need to update layer if
  985.     ** there is a below layer.  The bottom-most layer update doesn't do anything.
  986.     ** As a default, the bottom-most layer is considered background and does not
  987.     ** get updated. */
  988.  
  989.     if (theLayer) {
  990.         belowLayer = (*theLayer)->belowLayer;
  991.         if (belowLayer) {
  992.             /* Get this layer's GWorld and below layer's port. */
  993.             thisPort    = (*theLayer)->layerPort;
  994.             thisGDevice = (*theLayer)->layerGDevice;
  995.             belowPort   = (*belowLayer)->layerPort;
  996.  
  997.             /* Save current GWorld and set the parent's GWorld. */
  998.             SmartGetGWorld(&keepPort, &keepGDevice);
  999.             SmartSetGWorld((CGrafPtr)thisPort, thisGDevice);
  1000.  
  1001.             thisUpdate = UpdateUpdateRects(theLayer);
  1002.  
  1003.             rgn = NewRgn();
  1004.             RectRgn(rgn, &thisUpdate);
  1005.  
  1006.             belowRect = GetEffectiveSrcRect(belowLayer);
  1007.             thisRect  = GetEffectiveDstRect(theLayer);
  1008.  
  1009.                 /* As a default behavior, we CopyBits the below layer into this layer. */
  1010.             LockLayerWorld(belowLayer);
  1011.             LockLayerWorld(theLayer);
  1012.             xfer = (*theLayer)->xferMode;
  1013.             CopyBits(&belowPort->portBits, &thisPort->portBits, &belowRect, &thisRect, xfer, rgn);
  1014.             UnlockLayerWorld(theLayer);
  1015.             UnlockLayerWorld(belowLayer);
  1016.             DisposeRgn(rgn);
  1017.  
  1018.             SmartSetGWorld(keepPort, keepGDevice);        /* Restore to the kept GWorld. */
  1019.         }
  1020.     }
  1021.     return(noErr);
  1022. }
  1023.  
  1024.  
  1025.  
  1026. /*****************************************************************************/
  1027.  
  1028.  
  1029.  
  1030. static OSErr    DefaultLayerDispose(LayerObj theLayer)
  1031. {
  1032.     GWorldPtr    theWorld;
  1033.  
  1034.     if (theLayer) {
  1035.         if ((*theLayer)->layerOwnsPort) {
  1036.             theWorld = (GWorldPtr)(*theLayer)->layerPort;
  1037.             if (theWorld) {
  1038.                 if ((*theLayer)->layerBitmap)
  1039.                     KillLayerWorld(theLayer);
  1040.                 else
  1041.                     DisposeGWorld(theWorld);
  1042.             }
  1043.         }
  1044.     }
  1045.  
  1046.     return(noErr);
  1047. }
  1048.  
  1049.  
  1050.  
  1051. /*****************************************************************************/
  1052.  
  1053.  
  1054.  
  1055. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds)
  1056. {
  1057.     GrafPtr    oldPort;
  1058.     GrafPtr    newPort;
  1059.     Handle    bitmap;
  1060.     OSErr    err;
  1061.  
  1062.     OffsetRect(&bnds, -bnds.left, -bnds.top);    /* Make sure upper-left is 0,0. */
  1063.  
  1064.     GetPort(&oldPort);        /* Need this to restore the port after OpenPort. */
  1065.  
  1066.     newPort = (GrafPtr)NewPtr(sizeof(GrafPort));        /* Allocate the grafPort. */
  1067.     err = MemError();
  1068.     if (err)
  1069.         return(err);        /* Failed to allocate the off-screen port. */
  1070.  
  1071.     /* The call to OpenPort does the following:
  1072.     ** 1) allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  1073.     ** 2) sets portBits to screenBits
  1074.     ** 3) sets portRect to screenBits.bounds, etc. (see IM I-163,164)
  1075.     ** 4) side effect: does a SetPort(&offScreen) */
  1076.  
  1077.     OpenPort(newPort);
  1078.     SetPort(oldPort);
  1079.  
  1080.         /* Now make bitmap the size of the bounds that caller supplied. */
  1081.  
  1082.     newPort->portRect = bnds;
  1083.     newPort->portBits.bounds = bnds;
  1084.     RectRgn(newPort->visRgn, &bnds);
  1085.  
  1086.     SetRectRgn(newPort->clipRgn, -32000, -32000, 32000, 32000);
  1087.         /* Avoid wide-open clipRgn, to be safe.    */
  1088.  
  1089.     /* rowBytes is size of row, it must be rounded up to an even number of bytes. */
  1090.     newPort->portBits.rowBytes = ((bnds.right - bnds.left + 15) >> 4) << 1;
  1091.  
  1092.     bitmap = NewHandle(newPort->portBits.rowBytes * (long)(bnds.bottom - bnds.top));
  1093.     err = MemError();
  1094.     if (err) {
  1095.         ClosePort(newPort);            /* Dump the visRgn and clipRgn. */
  1096.         DisposePtr((Ptr)newPort);    /* Dump the GrafPort. */
  1097.         return(err);
  1098.     }
  1099.  
  1100.     (*theLayer)->layerBitmap = bitmap;
  1101.     *layerWorld              = (GWorldPtr)newPort;
  1102.  
  1103.     return(noErr);
  1104. }
  1105.  
  1106.  
  1107.  
  1108. /*****************************************************************************/
  1109.  
  1110.  
  1111.  
  1112. static void    KillLayerWorld(LayerObj theLayer)
  1113. {
  1114.     DisposeHandle((*theLayer)->layerBitmap);
  1115.     (*theLayer)->layerBitmap = nil;
  1116.  
  1117.     ClosePort((*theLayer)->layerPort);
  1118.     DisposePtr((Ptr)(*theLayer)->layerPort);
  1119.     (*theLayer)->layerPort = nil;
  1120. }
  1121.  
  1122.  
  1123.  
  1124.  
  1125. /*****************************************************************************/
  1126.  
  1127.  
  1128.  
  1129. static void    SmartGetGWorld(CGrafPtr *port, GDHandle *gdh)
  1130. {
  1131.     if (GetQDVersion())
  1132.         GetGWorld(port, gdh);
  1133.     else {
  1134.         *gdh = nil;
  1135.         GetPort((GrafPtr *)port);
  1136.     }
  1137. }
  1138.  
  1139.  
  1140.  
  1141. /*****************************************************************************/
  1142.  
  1143.  
  1144.  
  1145. static void    SmartSetGWorld(CGrafPtr port, GDHandle gdh)
  1146. {
  1147.     if (GetQDVersion())
  1148.         SetGWorld(port, gdh);
  1149.     else
  1150.         SetPort((GrafPtr)port);
  1151. }
  1152.  
  1153.  
  1154.  
  1155. /*****************************************************************************/
  1156.  
  1157.  
  1158.  
  1159. static short    GetQDVersion()
  1160. {
  1161.     static long    gestaltResult = -1;
  1162.  
  1163.     if (gestaltResult == -1) {
  1164.         if (Gestalt(gestaltQuickdrawVersion, &gestaltResult))
  1165.             gestaltResult = 0;
  1166.     }
  1167.  
  1168.     return((gestaltResult >> 8) & 0xFF);
  1169. }
  1170.  
  1171.  
  1172.  
  1173. /*****************************************************************************/
  1174.  
  1175.  
  1176.  
  1177. static short    GetSystemVersion()
  1178. {
  1179.     static long    gestaltResult;
  1180.  
  1181.     if (!gestaltResult) {
  1182.         if (Gestalt(gestaltSystemVersion, &gestaltResult))
  1183.             gestaltResult = 0;
  1184.     }
  1185.  
  1186.     return(gestaltResult);
  1187. }
  1188.  
  1189.  
  1190.  
  1191. /*****************************************************************************/
  1192.  
  1193.  
  1194.  
  1195. static Boolean    TrapExists(short theTrap)
  1196. {
  1197.     TrapType    theTrapType;
  1198.  
  1199.     theTrapType = GetTrapType(theTrap);
  1200.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
  1201.         theTrap = _Unimplemented;
  1202.  
  1203.     return(NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, theTrapType));
  1204. }
  1205.  
  1206.  
  1207.  
  1208. /*****************************************************************************/
  1209.  
  1210.  
  1211.  
  1212. static short    NumToolboxTraps(void)
  1213. {
  1214.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  1215.         return(0x200);
  1216.     else
  1217.         return(0x400);
  1218. }
  1219.  
  1220.  
  1221.  
  1222. /*****************************************************************************/
  1223.  
  1224.  
  1225.  
  1226. static TrapType    GetTrapType(short theTrap)
  1227. {
  1228.     /* OS traps start with A0, Tool with A8 or AA. */
  1229.     if ((theTrap & 0x0800) == 0)                    /* per D.A. */
  1230.         return(OSTrap);
  1231.     else
  1232.         return(ToolTrap);
  1233. }
  1234.  
  1235.  
  1236.  
  1237.